/*
 * Created by JFormDesigner on Wed Nov 21 11:32:27 CST 2018
 */

package cn.xo68.ide.plugin.common.ui.form;

import cn.xo68.core.PropertiesDocument;
import cn.xo68.core.date.DateTime;
import cn.xo68.ide.plugin.common.GuiUtils;
import cn.xo68.ide.plugin.common.PluginPathUtils;
import cn.xo68.ide.plugin.common.component.StarupApplicationComponent;
import cn.xo68.ide.plugin.common.component.ToolSuiteJobManager;
import cn.xo68.ide.plugin.common.domain.CodeGenerateInfo;
import cn.xo68.ide.plugin.common.domain.TableModuleConfig;
import cn.xo68.ide.plugin.common.job.LoadDatabaseMetaDataJob;
import cn.xo68.ide.plugin.common.jobs.CodeGenerateJob;
import cn.xo68.ide.plugin.common.jobs.DeleteGenerateCodeJob;
import cn.xo68.ide.plugin.common.jobs.SaveCodeGenerateInfoJob;
import cn.xo68.ide.plugin.common.jobs.SaveCodeGenerateModuleJob;
import cn.xo68.ide.plugin.common.service.CodeGenerateManager;
import cn.xo68.ide.plugin.common.swing.treetable.CheckTreeTableManager;
import cn.xo68.ide.plugin.common.template.TemplateConfig;
import cn.xo68.ide.plugin.common.template.TemplateItem;
import cn.xo68.ide.plugin.common.ui.generate.CodeGenerateNode;
import cn.xo68.ide.plugin.common.ui.generate.CodeGenerateNodeBuilder;
import cn.xo68.ide.plugin.common.ui.generate.CodeGenerateTableContext;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.wy2.generator.config.GeneratorConsts;
import com.wy2.generator.database.common.DatabaseMetaDataEntity;
import com.wy2.generator.database.entity.DatabaseTable;
import icons.WxIcons;
import org.jdesktop.swingx.JXTreeTable;
import org.jdesktop.swingx.treetable.DefaultTreeTableModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.File;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * @author wyy
 */
public class GenerateCodeDialog extends JDialog {

    private static Logger logger = LoggerFactory.getLogger(GenerateCodeDialog.class);

    public static void open(Project selectedProject, VirtualFile selectedFile){

        //logger.info(PluginConstants.getPluginDescriptor().getName());

        GenerateCodeDialog dialog=new GenerateCodeDialog(selectedProject, selectedFile);
        dialog.setIconImage(WxIcons.loadImage(WxIcons.PATH_CODE));
        GuiUtils.openDialog(dialog, "代码生成",700,500, true);

    }

    private final Project selectedProject;
    private final VirtualFile selectedFile;

    private CheckTreeTableManager checkTreeTableManager;
    private ChangeListener checkStateChangeListener;



    public GenerateCodeDialog(Project selectedProject, VirtualFile selectedFile) {
        super((Frame) GuiUtils.getIdeaWindow());

        this.selectedProject = selectedProject;
        this.selectedFile = selectedFile;

        checkStateChangeListener=new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                lbResult.setText(MessageFormat.format("已经选中{0}张数据表", getSelectedTables().size()));
            }
        };

        initComponents();

        bindData();
    }

    private List<String> getColumns(){
        ArrayList<String> columns=new ArrayList<>();
        columns.add("表名/字段名");
        columns.add("实体/字段");
        columns.add("模块");
        return  columns;
    }

    private void bindData(){

        CodeGenerateManager codeGenerateManager = CodeGenerateManager.getInstance();
        PropertiesDocument configDoc=codeGenerateManager.loadGenerateConfig(selectedFile);
        if(configDoc==null) {
            logger.error("加载配置失败，无法加载表信息");
            return;
        }
        tfPackages.setText(configDoc.getProperty(GeneratorConsts.GENERATOR_CONFIG_TEMPLATE_ATTRIBUTE_PREFIX+"."+ GeneratorConsts.TEMPLATE_ATTRI_BASEPACKAGE));

        //configDoc.setProperty(GeneratorConsts.GENERATOR_CONFIG_TEMPLATE_DIRECTORY, templateDirectory.getAbsolutePath());
        //configDoc.setProperty(GeneratorConsts.GENERATOR_CONFIG_OUTPUT_DIRECTORY, selectedFile.getCanonicalPath());

        StarupApplicationComponent starupApplicationComponent = StarupApplicationComponent.getInstance();
        TemplateConfig templateConfig = starupApplicationComponent.loadTemplateConfig();
        DefaultComboBoxModel<TemplateItem> comboBoxModel= new DefaultComboBoxModel<>(templateConfig.getCodeItems());
        cbTemplate.setModel(comboBoxModel);

        CodeGenerateInfo codeGenerateInfo = codeGenerateManager.loadCodeGenerateInfo(selectedFile);
        if(codeGenerateInfo!=null){
            cbTemplate.setSelectedItem(codeGenerateInfo.getTemplateItem());
        }

        DatabaseMetaDataEntity databaseMetaDataEntity=codeGenerateManager.loadLocalDatabaseMetaData(selectedFile);
        if(databaseMetaDataEntity==null){
            LoadDatabaseMetaDataJob job=new LoadDatabaseMetaDataJob("加载数据库元数据", this.selectedFile);
            getJobManager().submit(job);
            databaseMetaDataEntity=codeGenerateManager.loadLocalDatabaseMetaData(selectedFile);
        }

        xTreeTable1.setAutoResizeMode(JXTreeTable.AUTO_RESIZE_LAST_COLUMN);
        //xTreeTable1.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        //xTreeTable1.setColumnControlVisible(true);
        //xTreeTable1.setRootVisible(false);



        xTreeTable1.setShowGrid(true,true);

        TableModuleConfig moduleConfig = codeGenerateManager.loadTableModuleConfig(selectedFile);

        xTreeTable1.setTreeTableModel(new DefaultTreeTableModel(CodeGenerateNodeBuilder.getInstance().adapter(databaseMetaDataEntity, moduleConfig, codeGenerateInfo, checkStateChangeListener).build(),getColumns()));
        checkTreeTableManager=new CheckTreeTableManager(xTreeTable1);
        checkStateChangeListener.stateChanged(new ChangeEvent(this));
        //xTreeTable1.expandAll();



    }


    private void btnRefreshActionPerformed(ActionEvent e) {
        LoadDatabaseMetaDataJob job=new LoadDatabaseMetaDataJob("加载数据库元数据", this.selectedFile);
        getJobManager().submit(job);

        CodeGenerateManager codeGenerateManager = CodeGenerateManager.getInstance();
        DatabaseMetaDataEntity databaseMetaDataEntity=codeGenerateManager.loadLocalDatabaseMetaData(selectedFile);
        TableModuleConfig moduleConfig = codeGenerateManager.loadTableModuleConfig(selectedFile);
        CodeGenerateInfo codeGenerateInfo = codeGenerateManager.loadCodeGenerateInfo(selectedFile);
        xTreeTable1.setTreeTableModel(new DefaultTreeTableModel(CodeGenerateNodeBuilder.getInstance().adapter(databaseMetaDataEntity, moduleConfig, codeGenerateInfo, checkStateChangeListener).build(),getColumns()));
        checkTreeTableManager=new CheckTreeTableManager(xTreeTable1);

        checkStateChangeListener.stateChanged(new ChangeEvent(this));
        //xTreeTable1.expandAll();
    }

    private void btnAllNoSelActionPerformed(ActionEvent e) {
        checkTreeTableManager.selectedAll(false);
    }

    private void btnAllselActionPerformed(ActionEvent e) {
        checkTreeTableManager.selectedAll(true);
    }

    /**
     * 生成代码
     * @param e
     */
    private void btnGenerateActionPerformed(ActionEvent e) {


        saveTableModuleConfig();

        LinkedList<DatabaseTable> selectedTables= getSelectedTables();
        logger.info("table count:{}", selectedTables.size());
        CodeGenerateManager codeGenerateManager = CodeGenerateManager.getInstance();
        PropertiesDocument configDoc=codeGenerateManager.loadGenerateConfig(selectedFile);
        if(configDoc==null) {
            logger.error("加载配置失败，无法加载表信息");
            return;
        }
        TemplateItem selectTemplate = (TemplateItem) cbTemplate.getSelectedItem();
        String templateFolder=selectTemplate.getTemplateFolder();
        String packagesStr= tfPackages.getText().trim();



        //代码生成信息
        CodeGenerateInfo codeGenerateInfo=new CodeGenerateInfo();
        codeGenerateInfo.setGenerateTime(DateTime.Now().getDate());
        codeGenerateInfo.setBasePackage(packagesStr);
        codeGenerateInfo.setTemplateItem(selectTemplate);
        codeGenerateInfo.setTables(selectedTables);

        SaveCodeGenerateInfoJob job=new SaveCodeGenerateInfoJob("保存代码生成信息",selectedFile,codeGenerateInfo, selectedTables);
        getJobManager().submit(job);

        File templateDirectory=new File(PluginPathUtils.getTemplatePath(),templateFolder);
        configDoc.setProperty(GeneratorConsts.GENERATOR_CONFIG_TEMPLATE_DIRECTORY, templateDirectory.getAbsolutePath());
        configDoc.setProperty(GeneratorConsts.GENERATOR_CONFIG_OUTPUT_DIRECTORY, selectedFile.getCanonicalPath());


        Map<String,Object> model=new HashMap<>();
        //model.put(GeneratorConsts.TEMPLATE_ATTRI_PROJECT_NAME,"");
       //model.put(GeneratorConsts.TEMPLATE_ATTRI_ARTIFACT_ID,"");
        model.put(GeneratorConsts.TEMPLATE_ATTRI_BASEPACKAGE, packagesStr);

        CodeGenerateJob codeGenerateJob=new CodeGenerateJob("代码生成", selectedFile,configDoc, model, selectedTables, this);
        getJobManager().submit(codeGenerateJob);

        // dispose();

    }

    private void btnDeleteActionPerformed(ActionEvent e) {

        LinkedList<DatabaseTable> selectedTables= getSelectedTables();
        logger.info("table count:{}", selectedTables.size());
        CodeGenerateManager codeGenerateManager = CodeGenerateManager.getInstance();
        PropertiesDocument configDoc=codeGenerateManager.loadGenerateConfig(selectedFile);
        if(configDoc==null) {
            logger.error("加载配置失败，无法加载表信息");
            return;
        }
        TemplateItem selectTemplate = (TemplateItem) cbTemplate.getSelectedItem();
        String templateFolder=selectTemplate.getTemplateFolder();
        String packagesStr= tfPackages.getText().trim();

        File templateDirectory=new File(PluginPathUtils.getTemplatePath(),templateFolder);
        configDoc.setProperty(GeneratorConsts.GENERATOR_CONFIG_TEMPLATE_DIRECTORY, templateDirectory.getAbsolutePath());
        configDoc.setProperty(GeneratorConsts.GENERATOR_CONFIG_OUTPUT_DIRECTORY, selectedFile.getCanonicalPath());


        Map<String,Object> model=new HashMap<>();
        model.put(GeneratorConsts.TEMPLATE_ATTRI_PROJECT_NAME,"");
        model.put(GeneratorConsts.TEMPLATE_ATTRI_ARTIFACT_ID,"");
        model.put(GeneratorConsts.TEMPLATE_ATTRI_BASEPACKAGE, packagesStr);


        DeleteGenerateCodeJob deleteGenerateCodeJob=new DeleteGenerateCodeJob("删除生成代码", selectedFile,configDoc, model, selectedTables, this);
        getJobManager().submit(deleteGenerateCodeJob);

        //dispose();
    }

    /**
     * 保存表模块配置
     */
    private void saveTableModuleConfig() {
        LinkedList<DatabaseTable>  allTables = getAllTables();
        SaveCodeGenerateModuleJob job=new SaveCodeGenerateModuleJob("保存代码生成时模块信息",selectedFile, allTables);
        getJobManager().submit(job);
    }

    private  ToolSuiteJobManager getJobManager(){
        return this.selectedProject.getComponent(ToolSuiteJobManager.class);
    }

    /**
     * 返回根节点
     * @return
     */
    private CodeGenerateNode getRootNode(){
        Object obj = xTreeTable1.getTreeTableModel().getRoot();
        if(obj instanceof CodeGenerateNode){
            CodeGenerateNode rootNode= (CodeGenerateNode) obj;
            return rootNode;
        }
        return null;
    }

    private LinkedList<DatabaseTable> getAllTables(){
        LinkedList<DatabaseTable> tables= new LinkedList<>();
        CodeGenerateNode rootNode=getRootNode();
        if(rootNode!=null){
            for(int i=0;i< rootNode.getChildCount(); i++) {
                if(rootNode.getChildAt(i).getUserObject() instanceof CodeGenerateTableContext){
                    tables.add(((CodeGenerateTableContext) rootNode.getChildAt(i).getUserObject()).getContext());
                }
            }
        }
        return tables;
    }

    private LinkedList<DatabaseTable> getSelectedTables(){
        LinkedList<DatabaseTable> tables= new LinkedList<>();
        CodeGenerateNode rootNode=getRootNode();
        if(rootNode!=null){
            for(int i=0;i< rootNode.getChildCount(); i++) {
                if(rootNode.getChildAt(i).getUserObject() instanceof CodeGenerateTableContext && ((CodeGenerateTableContext) rootNode.getChildAt(i).getUserObject()).isChecked()){
                    tables.add(((CodeGenerateTableContext) rootNode.getChildAt(i).getUserObject()).getContext());
                }
            }
        }
        return tables;
    }


    public void SetResultInfo(String info){
        this.lbResult.setText(info);
    }


    private void initComponents() {
        // JFormDesigner - Component initialization - DO NOT MODIFY  //GEN-BEGIN:initComponents
        panel_form = new JPanel();
        label2 = new JLabel();
        tfPackages = new JTextField();
        label3 = new JLabel();
        cbTemplate = new JComboBox();
        label1 = new JLabel();
        scrollPane1 = new JScrollPane();
        xTreeTable1 = new JXTreeTable();
        panel_ops = new JPanel();
        btnRefresh = new JButton();
        btnGenerate = new JButton();
        btnDelete = new JButton();
        btnAllsel = new JButton();
        btnAllNoSel = new JButton();
        lbResult = new JLabel();

        //======== this ========
        setType(Window.Type.POPUP);
        Container contentPane = getContentPane();
        contentPane.setLayout(new GridBagLayout());
        ((GridBagLayout)contentPane.getLayout()).columnWidths = new int[] {308, 80, 0};
        ((GridBagLayout)contentPane.getLayout()).rowHeights = new int[] {66, 0, 0, 0, 0};
        ((GridBagLayout)contentPane.getLayout()).columnWeights = new double[] {1.0, 0.0, 1.0E-4};
        ((GridBagLayout)contentPane.getLayout()).rowWeights = new double[] {0.0, 0.0, 1.0, 0.0, 1.0E-4};

        //======== panel_form ========
        {
            panel_form.setLayout(new GridBagLayout());
            ((GridBagLayout)panel_form.getLayout()).columnWidths = new int[] {55, 0, 0};
            ((GridBagLayout)panel_form.getLayout()).rowHeights = new int[] {0, 0, 0};
            ((GridBagLayout)panel_form.getLayout()).columnWeights = new double[] {0.0, 1.0, 1.0E-4};
            ((GridBagLayout)panel_form.getLayout()).rowWeights = new double[] {0.0, 0.0, 1.0E-4};

            //---- label2 ----
            label2.setText("\u5305\u540d");
            panel_form.add(label2, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
                GridBagConstraints.EAST, GridBagConstraints.VERTICAL,
                new Insets(0, 0, 5, 5), 0, 0));
            panel_form.add(tfPackages, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0,
                GridBagConstraints.CENTER, GridBagConstraints.BOTH,
                new Insets(0, 0, 5, 0), 0, 0));

            //---- label3 ----
            label3.setText("\u6a21\u677f");
            panel_form.add(label3, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0,
                GridBagConstraints.EAST, GridBagConstraints.VERTICAL,
                new Insets(0, 0, 0, 5), 0, 0));
            panel_form.add(cbTemplate, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0,
                GridBagConstraints.CENTER, GridBagConstraints.BOTH,
                new Insets(0, 0, 0, 0), 0, 0));
        }
        contentPane.add(panel_form, new GridBagConstraints(0, 0, 2, 1, 0.0, 0.0,
            GridBagConstraints.CENTER, GridBagConstraints.BOTH,
            new Insets(0, 0, 6, 0), 0, 0));

        //---- label1 ----
        label1.setText("\u8bf7\u9009\u62e9\u8981\u751f\u6210\u7684\u8868");
        contentPane.add(label1, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0,
            GridBagConstraints.CENTER, GridBagConstraints.BOTH,
            new Insets(0, 0, 6, 6), 0, 0));

        //======== scrollPane1 ========
        {
            scrollPane1.setViewportView(xTreeTable1);
        }
        contentPane.add(scrollPane1, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0,
            GridBagConstraints.CENTER, GridBagConstraints.BOTH,
            new Insets(0, 0, 6, 6), 0, 0));

        //======== panel_ops ========
        {
            panel_ops.setLayout(new GridBagLayout());
            ((GridBagLayout)panel_ops.getLayout()).columnWidths = new int[] {0, 0};
            ((GridBagLayout)panel_ops.getLayout()).rowHeights = new int[] {0, 0, 0, 0, 0, 0};
            ((GridBagLayout)panel_ops.getLayout()).columnWeights = new double[] {1.0, 1.0E-4};
            ((GridBagLayout)panel_ops.getLayout()).rowWeights = new double[] {0.0, 0.0, 0.0, 0.0, 0.0, 1.0E-4};

            //---- btnRefresh ----
            btnRefresh.setText("\u5237\u65b0");
            btnRefresh.addActionListener(e -> btnRefreshActionPerformed(e));
            panel_ops.add(btnRefresh, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
                GridBagConstraints.CENTER, GridBagConstraints.BOTH,
                new Insets(0, 0, 5, 0), 0, 0));

            //---- btnGenerate ----
            btnGenerate.setText("\u751f\u6210");
            btnGenerate.addActionListener(e -> btnGenerateActionPerformed(e));
            panel_ops.add(btnGenerate, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0,
                GridBagConstraints.CENTER, GridBagConstraints.BOTH,
                new Insets(0, 0, 5, 0), 0, 0));

            //---- btnDelete ----
            btnDelete.setText("\u5220\u9664");
            btnDelete.addActionListener(e -> btnDeleteActionPerformed(e));
            panel_ops.add(btnDelete, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0,
                GridBagConstraints.CENTER, GridBagConstraints.BOTH,
                new Insets(0, 0, 5, 0), 0, 0));

            //---- btnAllsel ----
            btnAllsel.setText("\u5168\u9009");
            btnAllsel.addActionListener(e -> btnAllselActionPerformed(e));
            panel_ops.add(btnAllsel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0,
                GridBagConstraints.CENTER, GridBagConstraints.BOTH,
                new Insets(0, 0, 5, 0), 0, 0));

            //---- btnAllNoSel ----
            btnAllNoSel.setText("\u5168\u4e0d\u9009");
            btnAllNoSel.addActionListener(e -> btnAllNoSelActionPerformed(e));
            panel_ops.add(btnAllNoSel, new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0,
                GridBagConstraints.CENTER, GridBagConstraints.BOTH,
                new Insets(0, 0, 0, 0), 0, 0));
        }
        contentPane.add(panel_ops, new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0,
            GridBagConstraints.CENTER, GridBagConstraints.BOTH,
            new Insets(0, 0, 6, 0), 0, 0));

        //---- lbResult ----
        lbResult.setText("\u5df2\u9009\u4e2d0\u5f20\u8868");
        contentPane.add(lbResult, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0,
            GridBagConstraints.EAST, GridBagConstraints.VERTICAL,
            new Insets(0, 0, 0, 6), 0, 0));
        pack();
        setLocationRelativeTo(getOwner());
        // JFormDesigner - End of component initialization  //GEN-END:initComponents
    }

    // JFormDesigner - Variables declaration - DO NOT MODIFY  //GEN-BEGIN:variables
    private JPanel panel_form;
    private JLabel label2;
    private JTextField tfPackages;
    private JLabel label3;
    private JComboBox cbTemplate;
    private JLabel label1;
    private JScrollPane scrollPane1;
    private JXTreeTable xTreeTable1;
    private JPanel panel_ops;
    private JButton btnRefresh;
    private JButton btnGenerate;
    private JButton btnDelete;
    private JButton btnAllsel;
    private JButton btnAllNoSel;
    private JLabel lbResult;
    // JFormDesigner - End of variables declaration  //GEN-END:variables
}
